package com.kakarote.oa.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.TypeUtils;
import com.kakarote.common.field.utils.FieldUtil;
import com.kakarote.core.common.Const;
import com.kakarote.core.common.Result;
import com.kakarote.core.common.enums.CrmRelationTypeEnum;
import com.kakarote.core.common.enums.FieldEnum;
import com.kakarote.core.common.enums.SystemCodeEnum;
import com.kakarote.core.entity.BasePage;
import com.kakarote.core.entity.CrmRelationDTO;
import com.kakarote.core.entity.UserInfo;
import com.kakarote.core.exception.CrmException;
import com.kakarote.core.feign.admin.entity.*;
import com.kakarote.core.feign.admin.service.AdminFileService;
import com.kakarote.core.feign.admin.service.AdminMessageService;
import com.kakarote.core.feign.admin.service.AdminService;
import com.kakarote.core.feign.crm.entity.BiParams;
import com.kakarote.core.feign.crm.entity.SimpleCrmEntity;
import com.kakarote.core.servlet.ApplicationContextHolder;
import com.kakarote.core.servlet.BaseServiceImpl;
import com.kakarote.core.utils.*;
import com.kakarote.oa.common.ActionRecordUtil;
import com.kakarote.oa.common.OaCodeEnum;
import com.kakarote.oa.constart.SubmitType;
import com.kakarote.oa.entity.BO.LogBO;
import com.kakarote.oa.entity.BO.LogSaveBO;
import com.kakarote.oa.entity.BO.OaLogExportBO;
import com.kakarote.oa.entity.PO.*;
import com.kakarote.oa.entity.VO.OaBusinessNumVO;
import com.kakarote.oa.entity.VO.OaLogTemplateConfigVO;
import com.kakarote.oa.entity.VO.OaLogTemplateFieldVO;
import com.kakarote.oa.entity.VO.OaLogVO;
import com.kakarote.oa.mapper.OaLogMapper;
import com.kakarote.oa.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.kakarote.core.servlet.ApplicationContextHolder.getBean;

/**
 * <p>
 * 工作日志表 服务实现类
 * </p>
 *
 * @author wyq
 * @since 2020-05-15
 */
@Service
public class OaLogServiceImpl extends BaseServiceImpl<OaLogMapper, OaLog> implements IOaLogService {

    @Autowired
    private AdminService adminService;

    @Autowired
    private AdminFileService adminFileService;


    @Autowired
    private IOaLogRelationService logRelationService;

    @Autowired
    private IOaLogRecordService logRecordService;

    @Autowired
    private IOaLogBulletinService logBulletinService;

    @Autowired
    private IOaLogUserFavourService oaLogUserFavourService;

    @Autowired
    private IOaLogDataService oaLogDataService;

    @Autowired
    private IOaLogTemplateFieldService oaLogTemplateFieldService;

    @Autowired
    private IOaLogTemplateConfigService oaLogTemplateConfigService;

    private static final String USER_IDS = "userIds";

    private static final int FIVE = 5;

    private static final int TWO = 2;

    private static final int THREE = 3;

    private static final String CRM_TYPE = "crmType";

    private static final String RECENT_30 = "recent30";

    private static final String RECENT_60 = "recent60";

    private static final String SEGEX = ",";


    @Override
    public List<OaLogTemplateFieldVO> queryDefaultField(Long configId) {
        List<OaLogTemplateFieldVO> filedList = oaLogTemplateFieldService.queryField(configId, null);
        filedList.add(new OaLogTemplateFieldVO("updateTime", FieldEnum.DATETIME, 1));
        filedList.add(new OaLogTemplateFieldVO("createTime", FieldEnum.DATETIME, 1));
        filedList.add(new OaLogTemplateFieldVO("createUserId", FieldEnum.USER, 1));
        return filedList;
    }

    /**
     * 分页查询日志列表
     *
     * @param bo bo
     * @return com.kakarote.core.entity.BasePage<com.kakarote.oa.entity.VO.OaLogVO>
     * @author jiao sir
     * @date 2021/8/3
     */
    @Override
    public BasePage<OaLogVO> queryLogList(LogBO bo) {
        handleLogBo(bo);
        // 增加查询扩展字段表
        if (ObjectUtil.isNotNull(bo.getSearch())) {
            List<Long> dataIds = oaLogDataService.getDataIdsBySearch(bo.getSearch());
            if (CollUtil.isNotEmpty(dataIds)) {
                bo.setLogIds(dataIds);
            }
        }
        if(bo.getIsSearch()!=null&&bo.getIsSearch()&&CollUtil.isEmpty(bo.getSearchUserIds())){
            return new BasePage<>(bo.getPage(),bo.getLimit(),0L,null);
        }
        BasePage<OaLogVO> basePage = getBaseMapper().queryLogList(bo.parse(), bo);
        // 处理列表
        handleLogList(basePage.getList());
        return basePage;
    }

    /**
     * 随机获取一条日志欢迎语
     *
     * @return data
     */
    @Override
    public String getLogWelcomeSpeech() {
        List<AdminConfig> speech = adminService.queryConfigByName("logWelcomeSpeech").getData();
        if (CollUtil.isEmpty(speech)) {
            return "";
        }
        return RandomUtil.randomEle(speech).getValue();
    }

    /**
     * 查询日志统计信息
     *
     * @return data
     */
    @Override
    public JSONObject queryLogBulletin() {
        Date beginTime = DateUtil.beginOfMonth(new Date());
        Date endTime = DateUtil.endOfMonth(new Date());
        Long userId = UserUtil.getUserId();
        return getBaseMapper().queryLogBulletin(userId, beginTime, endTime);
    }

    /**
     * 查询日志完成情况统计
     * 根据模板id 查询到日志模板的配置，根据配置去查询数据
     */
    @Override
    public JSONObject queryCompleteStats(Long configId) {
        OaLogTemplateConfigVO detail = oaLogTemplateConfigService.detail(configId, false);
        if (ObjectUtil.isNull(detail)) {
            return new JSONObject().fluentPut("status", 0);
        }
        if (ObjectUtil.equal(detail.getRuleStatus(), 0)) {
            return new JSONObject().fluentPut("status", 0);
        }
        JSONObject kv = this.getCycleTime(detail);
        if (kv.isEmpty() || kv.getJSONArray(USER_IDS).isEmpty()) {
            return new JSONObject().fluentPut("totalNum", 0).fluentPut("completeNum", 0);
        }
        Integer completeNum = getBaseMapper().queryCompleteStats(kv);
        return new JSONObject().fluentPut("totalNum", kv.get("totalNum")).fluentPut("completeNum", completeNum);
    }

    @Override
    public BasePage<JSONObject> queryCompleteOaLogList(LogBO bo) {
        Long categoryId = bo.getCategoryId();
        OaLogTemplateConfigVO detail = oaLogTemplateConfigService.detail(categoryId, false);
        if (ObjectUtil.isNull(detail)) {
            return new BasePage<>();
        }
        if (ObjectUtil.equal(detail.getRuleStatus(), 0)) {
            return new BasePage<>();
        }
        // 获取规则的一些统计数据
        JSONObject kv = this.getCycleTime(detail);
        if (ObjectUtil.isEmpty(kv) || kv.getJSONArray(USER_IDS).isEmpty()) {
            return new BasePage<>();
        }
        String search = bo.getSearch();
        if (StrUtil.isNotEmpty(search)) {
            kv.fluentPut("search", search);
        }
        // 获取日志的userIds
        JSONObject object = this.getLogListObject(bo);
        kv.fluentPut("isAdmin", object.get("isAdmin"))
                .fluentPut("userIds1", object.get("userIds1"))
                .fluentPut("userIds2", object.get("userIds2"))
                .fluentPut("send_user_ids", object.get("send_user_ids"));
        BasePage<JSONObject> page = getBaseMapper().queryCompleteOaLogList(bo.parse(), kv);
        List<Long> logIds = getLogIds(page.getList());
        if (logIds.size() == 0) {
            return page;
        }
        // 查询relationMap
        Map<Long, CrmRelationDTO> relationMap = getOaLogRelationMap(logIds);
        // 处理
        page.getList().forEach(log -> {
            queryLogDetail(log, UserUtil.getUserId(), relationMap);
            oaLogDataService.setData(log, log.getLong("logId"));
        });
        return page;
    }


    @Override
    public BasePage<SimpleUser> queryIncompleteOaLogList(LogBO bo) {
        Long categoryId = bo.getCategoryId();
        OaLogTemplateConfigVO detail = oaLogTemplateConfigService.detail(categoryId, false);
        if (Objects.equals(detail.getRuleStatus(), 0)) {
            return new BasePage<>();
        }
        JSONObject kv = this.getCycleTime(detail);
        if (ObjectUtil.isEmpty(kv) || kv.getJSONArray(USER_IDS).isEmpty()) {
            return new BasePage<>();
        }
        String search = bo.getSearch();
        if (StrUtil.isNotEmpty(search)) {
            kv.put("search", search);
        }
        List<OaLog> list = lambdaQuery()
                .select(OaLog::getCreateUserId)
                .eq(OaLog::getCategoryId, categoryId)
                .between(OaLog::getCreateTime, kv.getString("start"), kv.getString("end"))
                .in(OaLog::getCreateUserId, kv.getJSONArray("userIds"))
                .list();
        List<Long> ids = list.stream().map(OaLog::getCreateUserId).collect(Collectors.toList());
        if (ids.size() == 0) {
            ids.add(0L);
        }
        kv.put("notIds", ids);
        return getBaseMapper().queryIncompleteOaLogList(bo.parse(), kv);
    }


    /**
     * 日志自定义消息范围
     * 或者
     * 模板配置的消息范围
     *
     * @param oaLog log
     */
    private void sendOaMessage(OaLog oaLog) {
        // 日志模板
        Long categoryId = oaLog.getCategoryId();
        OaLogTemplateConfigVO configDetail = oaLogTemplateConfigService.detail(categoryId, false);
        // 如果没有选择默认发送范围，也没有勾选允许自定义添加发送范围，则不抄送
        if (
                ObjectUtil.isNull(configDetail.getSendDeptIdList())
                        && ObjectUtil.isNull(configDetail.getSendUserIdList())
                        && ObjectUtil.isNull(configDetail.getParentLevelList())
                        && ObjectUtil.equal(configDetail.getCustomSend(), 0)
        ) {
            return;
        }

        // 发送消息start
        AdminMessageBO adminMessageBO = new AdminMessageBO();
        adminMessageBO.setTitle(DateUtil.today());
        adminMessageBO.setUserId(UserUtil.getUserId());
        adminMessageBO.setTypeId(oaLog.getLogId());
        adminMessageBO.setMessageType(AdminMessageEnum.OA_LOG_SEND.getType());
        // 用户自定义的
        List<Long> ids = StrUtil.splitTrim(oaLog.getSendUserIds(), Const.SEPARATOR).stream().map(Long::valueOf).collect(Collectors.toList());
        List<String> deptIds = StrUtil.splitTrim(oaLog.getSendDeptIds(), Const.SEPARATOR);
        if (deptIds.size() > 0) {
            List<Long> longList = adminService.queryUserByDeptIds(deptIds.stream().map(Long::valueOf).collect(Collectors.toList())).getData();
            ids.addAll(longList);
        }

        // 模板配置-发送部门
        List<Long> sendDeptIdList = configDetail.getSendDeptIdList();
        if (CollUtil.isNotEmpty(sendDeptIdList)) {
            List<Long> sendDeptId2UserIdList = adminService.queryUserByDeptIds(sendDeptIdList).getData();
            ids.addAll(sendDeptId2UserIdList);
        }
        // 模板配置-发送用户
        List<Long> sendUserIdList = configDetail.getSendUserIdList();
        if (CollUtil.isNotEmpty(sendUserIdList)) {
            ids.addAll(sendUserIdList);
        }
        // 模板配置-发送上级
        List<Long> parentUserIds = oaLogTemplateConfigService.searchParentUserIds(configDetail.getParentLevelList());
        ids.addAll(parentUserIds);
        // 发送
        if (ids.size() > 0) {
            adminMessageBO.setContent(oaLog.getContent());
            adminMessageBO.setIds(CollUtil.distinct(ids));
            ApplicationContextHolder.getBean(AdminMessageService.class).sendMessage(adminMessageBO);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAndUpdate(LogSaveBO object) {
        UserInfo user = UserUtil.getUser();
        Long categoryId = object.getCategoryId();
        OaLogTemplateConfig templateConfig = oaLogTemplateConfigService.getById(categoryId);


        if (!Objects.equals(templateConfig.getSubmitType(), SubmitType.NONE.getType())) {
            SubmitType submitType = SubmitType.valueOf(templateConfig.getSubmitType());
            String startTime = submitType.getStartTime(new Date());
            String endTime = submitType.getEndTime(new Date());

            Long count = this.lambdaQuery().eq(OaLog::getCreateUserId, user.getUserId())
                    .eq(OaLog::getCategoryId, categoryId)
                    .between(OaLog::getCreateTime, startTime, endTime)
                    .ne(ObjectUtil.isNotNull(object.getLogId()), OaLog::getLogId, object.getLogId())
                    .count();
            if (count.intValue() >= templateConfig.getSubmitCount()) {
                throw new CrmException(OaCodeEnum.OA_SUBMIT_LOG_ERROR);
            }
        }


        OaLog oaLog = BeanUtil.copyProperties(object, OaLog.class);
        OaLogRelation oaLogRelation = BeanUtil.copyProperties(object, OaLogRelation.class);
        oaLog.setCreateUserId(user.getUserId());
        oaLog.setReadUserIds(",,");
        oaLog.setSendUserIds(SeparatorUtil.fromString(oaLog.getSendUserIds()));
        oaLog.setSendDeptIds(SeparatorUtil.fromString(oaLog.getSendDeptIds()));
        // 生成日志id
        Long logId = ObjectUtil.isNull(oaLog.getLogId()) ? BaseUtil.getNextId() : oaLog.getLogId();
        if (oaLog.getLogId() != null) {
            OaLog oldLog = getById(oaLog.getLogId());
            if (oldLog == null || !Objects.equals(user.getUserId(), oldLog.getCreateUserId())) {
                throw new CrmException(SystemCodeEnum.SYSTEM_NO_AUTH);
            }
            oaLog.setCreateTime(oldLog.getCreateTime());
            updateById(oaLog);
            logBulletinService.lambdaUpdate().eq(OaLogBulletin::getLogId, oaLog.getLogId()).remove();
            logRecordService.lambdaUpdate().eq(OaLogRecord::getLogId, oaLog.getLogId()).remove();
            saveLogRecord(oaLog.getLogId(), object.getGetBulletin(), templateConfig.getType());
        } else {
            oaLog.setLogId(logId);
            oaLog.setCreateTime(LocalDateTime.now());
            // 自定义字段值
            List<OaLogTemplateFieldVO> fields = queryDefaultField(oaLog.getCategoryId()).stream().filter(data -> FieldEnum.SERIAL_NUMBER.getType().equals(data.getType())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(fields)) {
                Map<String, Object> map = BeanUtil.beanToMap(oaLog);
                object.getField().forEach(f -> map.put(f.getFieldName(), f.getValue()));
                fields.forEach(fff -> object.getField().stream().filter(f -> ObjectUtil.equal(f.getFieldId(), fff.getFieldId())).forEach(f -> f.setValue(getBean(IOaLogFieldNumberDataService.class).generateNumber(fff, map))));
            }
            oaLog.setCreateTime(LocalDateTimeUtil.now());
            save(oaLog);
            saveLogRecord(oaLog.getLogId(), object.getGetBulletin(), templateConfig.getType());
        }
        // 保存扩展字段值
        oaLogDataService.saveData(object.getField(), logId);
        // 根据日志消息范围发送
        this.sendOaMessage(oaLog);

        if (oaLogRelation != null) {
            // 删除关系
            logRelationService.lambdaUpdate().eq(OaLogRelation::getLogId, logId).remove();
            // 获取关联的业务转集合//TODO 可以让前端直接传入集合
            List<OaLogRelation> oaLogRelations = new ArrayList<>(16);
            // 处理审批关联
            List<Long> customerIds = new ArrayList<>();
            List<Long> contactsIds = new ArrayList<>();
            List<Long> businessIds = new ArrayList<>();
            List<Long> contractIds = new ArrayList<>();
            List<Long> receivablesIds = new ArrayList<>();
            handleOaLogRelation(logId, CrmRelationTypeEnum.CUSTOMER.getType(), oaLogRelation.getCustomerIds(), oaLogRelations, customerIds);
            handleOaLogRelation(logId, CrmRelationTypeEnum.CONTACTS.getType(), oaLogRelation.getContactsIds(), oaLogRelations, contactsIds);
            handleOaLogRelation(logId, CrmRelationTypeEnum.BUSINESS.getType(), oaLogRelation.getBusinessIds(), oaLogRelations, businessIds);
            handleOaLogRelation(logId, CrmRelationTypeEnum.CONTRACT.getType(), oaLogRelation.getContractIds(), oaLogRelations, contractIds);
            handleOaLogRelation(logId, CrmRelationTypeEnum.RECEIVABLES.getType(), oaLogRelation.getReceivablesIds(), oaLogRelations, receivablesIds);
            logRelationService.saveBatch(oaLogRelations, oaLogRelations.size());
            //crmService.addActivity(2, 8, logId);
        }
    }


    /**
     * 根据id删除日志
     *
     * @param logId 日志ID
     * @author zhangzhiwei
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteById(Long logId) {
        OaLog oaLog = getById(logId);
        if (oaLog != null) {
            // 删除自定义字段值
            oaLogDataService.deleteByDataId(Collections.singletonList(logId));

            // 删除关系
            logRelationService
                    .lambdaUpdate()
                    .eq(OaLogRelation::getLogId, logId)
                    .remove();
            adminFileService.delete(oaLog.getBatchId());
            removeById(logId);
            //commentService.deleteComment(2, logId);
        }
    }


    @Override
    public BasePage<JSONObject> queryLogBulletinByType(LogBO bo) {
        UserInfo userInfo = UserUtil.getUser();
        String search = bo.getSearch();
        Integer crmType = bo.getCrmType();
        String camelField = bo.getSortField();
        String sortField = StrUtil.toUnderlineCase(camelField);
        if (!isValid(sortField)) {
            throw new CrmException(SystemCodeEnum.SYSTEM_NO_VALID);
        }
        Integer order = bo.getOrder();
        Integer today = bo.getToday();
        String orderType = "asc";
        if (order != null) {
            orderType = order == 1 ? "asc" : "desc";
        }
        Integer type = Integer.valueOf(bo.getType());
        List<Long> typeIds = new ArrayList<>();
        if (Objects.equals(today, 1)) {
            Date date = new Date();
            List<OaLogBulletin> bulletinList = getBaseMapper().queryBulletinByLogInfo(Collections.singletonList(userInfo.getUserId()), DateUtil.beginOfDay(date), DateUtil.endOfDay(date));
            bulletinList.forEach(oaLogBulletin -> {
                if (oaLogBulletin.getType().equals(type)) {
                    typeIds.add(oaLogBulletin.getTypeId());
                }
            });
        } else {
            List<OaLogBulletin> oaLogBulletins = logBulletinService.lambdaQuery().select(OaLogBulletin::getTypeId).eq(OaLogBulletin::getLogId, bo.getLogId()).eq(OaLogBulletin::getType, type).list();
            typeIds.addAll(oaLogBulletins.stream().map(OaLogBulletin::getTypeId).collect(Collectors.toList()));
        }
        if (typeIds.isEmpty()) {
            return new BasePage<>();
        }
        JSONObject object = new JSONObject()
                .fluentPut("type", type)
                //ghb修改bug增加 companyId sql中需要该参数
                .fluentPut("typeIds", typeIds)
                .fluentPut("search", search)
                .fluentPut("sortField", sortField)
                .fluentPut("orderType", orderType)
                .fluentPut("crmType", crmType);
        BasePage<JSONObject> paginate = getBaseMapper().queryLogBulletinByType(bo.parse(), object);
        if (type == FIVE) {
            // 字段配置
            List<OaLogTemplateFieldVO> activityFields = this.handleActivityFields();
            paginate.getList().forEach(f -> this.handleRelationAndPutValue2Fields(activityFields, f));
        }
        return paginate;
    }

    private void handleRelationAndPutValue2Fields(List<OaLogTemplateFieldVO> information, JSONObject crmModel) {
        // 关联信息
        this.buildActivityRelation(crmModel);
        List<OaLogTemplateFieldVO> fields = new ArrayList<>();
        // 获取跟进记录 扩展字段值
        this.getActivityFieldData(crmModel);
        information.forEach(field -> {
            OaLogTemplateFieldVO vos = BeanUtil.copyProperties(field, OaLogTemplateFieldVO.class);
            FieldEnum typeEnum = FieldEnum.parse(vos.getType());
            String fieldName = StrUtil.toCamelCase(vos.getFieldName());
            if (!crmModel.isEmpty()) {
                Object value = crmModel.get(fieldName);
                if (ObjectUtil.isEmpty(value)) {
                    vos.setValue(null);
                } else {
                    Object dataValue = FieldUtil.format2Object(value, typeEnum);
                    vos.setValue(dataValue);
                }
            }
            if (typeEnum != FieldEnum.DATE_INTERVAL) {
                oaLogTemplateFieldService.recordToFormType(vos, typeEnum);
            }
            fields.add(vos);
        });
        List<OaLogTemplateFieldVO> append = this.appendInformation(crmModel);
        fields.addAll(append);
        crmModel.put("fieldList", fields);
    }

    private void getActivityFieldData(JSONObject crmModel) {
        List<JSONObject> dataList = this.getBaseMapper().getActivityFieldData( TypeUtils.castToLong(crmModel.get("id")));
        if (CollUtil.isNotEmpty(dataList)) {
            for (JSONObject data : dataList) {
                crmModel.put(data.get("name").toString(), data.get("value"));
            }
        }
    }

    /**
     * TODO 此处对应 crm模块中 CrmActivityServiceImpl 中 handleRelationAndPutValue2Fields的方法处理跟进记录字段  ,若修改请同步修改
     */
    private List<OaLogTemplateFieldVO> handleActivityFields() {
        List<OaLogTemplateFieldVO> activityFields = oaLogTemplateFieldService.queryActivityFields();
        List<OaLogTemplateFieldVO> fieldList = activityFields.stream().map(field -> {
            OaLogTemplateFieldVO crmModelFiled = BeanUtil.copyProperties(field, OaLogTemplateFieldVO.class);
            FieldEnum typeEnum = FieldEnum.parse(crmModelFiled.getType());
            oaLogTemplateFieldService.recordToFormType(crmModelFiled, typeEnum);
            return crmModelFiled;
        }).collect(Collectors.toList());
        return fieldList;
    }

    private List<OaLogTemplateFieldVO> appendInformation(JSONObject crmModel) {
        List<OaLogTemplateFieldVO> filedVOS = new ArrayList<>();
        Object value = UserCacheUtil.getSimpleUsers(Collections.singletonList((Long) crmModel.get("createUserId")));
        filedVOS.add(new OaLogTemplateFieldVO("create_user_name", FieldEnum.USER, "创建人", 1).setValue(value));
        filedVOS.add(new OaLogTemplateFieldVO("create_time", FieldEnum.DATETIME, "创建时间", 1).setValue(crmModel.get("createTime")));
        filedVOS.forEach(f -> f.setSysInformation(1));
        return filedVOS;
    }

    @Override
    public List<JSONObject> queryLogRecordCount(String logId, Integer today, String sortField, Integer order) {
        List<Long> typeIds = new ArrayList<>();
        if (Objects.equals(today, 1)) {
            Date date = new Date();
            List<OaLogBulletin> bulletinList = getBaseMapper().queryBulletinByLogInfo(Collections.singletonList(UserUtil.getUserId()), DateUtil.beginOfDay(date), DateUtil.endOfDay(date));
            bulletinList.forEach(oaLogBulletin -> {
                if (oaLogBulletin.getType().equals(FIVE)) {
                    typeIds.add(oaLogBulletin.getTypeId());
                }
            });
        } else {
            List<OaLogBulletin> oaLogBulletins = logBulletinService.lambdaQuery().select(OaLogBulletin::getTypeId).eq(OaLogBulletin::getLogId, logId).eq(OaLogBulletin::getType, 5).list();
            typeIds.addAll(oaLogBulletins.stream().map(OaLogBulletin::getTypeId).collect(Collectors.toList()));
        }
        if (typeIds.isEmpty()) {
            typeIds.add(0L);
        }
        List<JSONObject> recordList = getBaseMapper().queryLogRecordCount(typeIds, sortField, order);
        if (recordList.stream().noneMatch(record -> Objects.equals(1, record.getInteger(CRM_TYPE)))) {
            recordList.add(new JSONObject().fluentPut("crmType", 1).fluentPut("count", 0));
        }
        if (recordList.stream().noneMatch(record -> Objects.equals(TWO, record.getInteger(CRM_TYPE)))) {
            recordList.add(new JSONObject().fluentPut("crmType", 2).fluentPut("count", 0));
        }
        if (recordList.stream().noneMatch(record -> Objects.equals(THREE, record.getInteger(CRM_TYPE)))) {
            recordList.add(new JSONObject().fluentPut("crmType", 3).fluentPut("count", 0));
        }
        if (recordList.stream().noneMatch(record -> Objects.equals(FIVE, record.getInteger(CRM_TYPE)))) {
            recordList.add(new JSONObject().fluentPut("crmType", 5).fluentPut("count", 0));
        }
        int six = 6;
        if (recordList.stream().noneMatch(record -> Objects.equals(six, record.getInteger(CRM_TYPE)))) {
            recordList.add(new JSONObject().fluentPut("crmType", 6).fluentPut("count", 0));
        }
        return recordList;
    }

    private void buildActivityRelation(JSONObject record) {
        String status = "status";
        if (record.getInteger(status) == 1) {
            String batchId = "batchId";
            if (StrUtil.isNotEmpty(record.getString(batchId))) {
                List<FileEntity> fileEntities = adminFileService.queryFileList(record.getString("batchId")).getData();
                Map<String, List<FileEntity>> collect = fileEntities.stream().collect(Collectors.groupingBy(FileEntity::getFileType));
                if (collect.isEmpty()) {
                    record.put("img", new ArrayList<>());
                    record.put("file", new ArrayList<>());
                } else {
                    record.putAll(collect);
                }
            } else {
                record.put("img", new ArrayList<>());
                record.put("file", new ArrayList<>());
            }
        }
        String createUserId = "createUserId";
        if (record.containsKey(createUserId)) {
            record.put("createUser", UserCacheUtil.getSimpleUser(record.getLong("createUserId")));
        }
        String activityType = "activityType";
        if (record.getInteger(activityType) == TWO) {
            String businessIds = record.getString("businessIds");
            List<SimpleCrmEntity> businessList = new ArrayList<>();
            String contactsIds = record.getString("contactsIds");
            List<SimpleCrmEntity> contactsList = new ArrayList<>();

            record.fluentPut("businessList", businessList).fluentPut("contactsList", contactsList);
        }

        if (!ObjectUtil.isEmpty(record.get("content"))) {
            Object content = record.get("content");
            JSONObject jsonObject;
            if (BaseUtil.isJSONObject(content.toString()) && ObjectUtil.notEqual(1, record.getInteger("type"))) {
                try {
                    jsonObject = JSONObject.parseObject(content.toString());
                    record.put("content", jsonObject);
                } catch (JSONException e) {
                    record.put("content", content);
                }
            } else {
                record.put("content", content);
            }
        }
    }

    private boolean isValid(String param) {
        if (param == null) {
            return true;
        }
        String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)| (\\b(select|update|union|and|or|delete|insert|trancate|char|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";
        Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
        return !sqlPattern.matcher(param).find();
    }

    private JSONObject getLogListObject(LogBO bo) {
        JSONObject object = new JSONObject(BeanUtil.beanToMap(bo));
        UserInfo user = UserUtil.getUser();
        //getIntValue 为空会返回0
        Integer by = bo.getBy();
        if (by == null) {
            by = 0;
        }
        BiParams biParams = new BiParams();
        biParams.setType(bo.getType());
        BiTimeUtil.BiTimeEntity recordInfo = BiTimeUtil.analyzeTime(biParams);
        if (RECENT_30.equals(bo.getType())) {
            object.fluentPut("recentDays", "30");
        } else if (RECENT_60.equals(bo.getType())) {
            object.fluentPut("recentDays", "60");
        }
        object.put("by", by);
        String createUserIdOne = bo.getCreateUserId();
        String createUserIdTwo = bo.getCreateUserId();
        if (StrUtil.isEmpty(createUserIdOne) && CollUtil.isEmpty(bo.getDeptIds())) {
            object.put("isAdmin", UserUtil.isAdmin());
        }
        List<Long> longList = adminService.queryChildUserId(user.getUserId()).getData();
        longList.add(user.getUserId());
        if (!UserUtil.isAdmin()) {
            List<Long> userIdList = StrUtil.splitTrim(createUserIdOne, Const.SEPARATOR).stream().map(Long::valueOf).collect(Collectors.toList());
            userIdList.retainAll(longList);
            createUserIdOne = StrUtil.join(Const.SEPARATOR, userIdList);
        }
        List<Long> createUserIdOneList = new ArrayList<>();
        if (StrUtil.isNotEmpty(createUserIdOne) && !SEGEX.equals(createUserIdOne)) {
            createUserIdOneList = Arrays.stream(createUserIdOne.split(",")).map(Long::parseLong).collect(Collectors.toList());
        }
        List<Long> createUserIdTwoList = new ArrayList<>();
        if (StrUtil.isNotEmpty(createUserIdTwo) && !SEGEX.equals(createUserIdTwo)) {
            createUserIdTwoList = Arrays.stream(createUserIdTwo.split(",")).map(Long::parseLong).collect(Collectors.toList());
        }
        if (CollUtil.isNotEmpty(bo.getDeptIds())) {
            List<Long> userIds = adminService.queryUserByDeptIds(bo.getDeptIds()).getData();
            if (!UserUtil.isAdmin()) {
                userIds.retainAll(longList);
            }
            createUserIdOneList.addAll(userIds);
            createUserIdTwoList.addAll(userIds);
        }
        List<Long> userIds = new ArrayList<>();
        if (by.equals(1)) {
            userIds.add(user.getUserId());
        } else if (by.equals(TWO)) {
            object.put("send_user_ids", user.getUserId());
            if (createUserIdTwoList.size() > 0) {
                userIds.addAll(createUserIdTwoList);
            }
        } else if (by.equals(0)) {
            if (createUserIdTwoList.size() > 0) {
                object.put("userIds1", createUserIdOneList);
                object.put("userIds2", createUserIdTwoList);
            } else {
                userIds.addAll(longList);
                object.put("userIds1", userIds);
            }
            object.put("send_user_ids", user.getUserId());
        }
        if (!RECENT_30.equals(bo.getType()) && !RECENT_60.equals(bo.getType()) && bo.getType() != null) {
            object.putAll(BeanUtil.beanToMap(recordInfo));
        }
        object.put("userIds", userIds);
        if (bo.getType() == null) {
            //type== null 是自定义时间 需要把时间放到参数中
            BeanUtil.beanToMap(bo).forEach((key, value) -> {
                if (value != null) {
                    object.put(key, value);
                }
            });
        }
        return object;
    }

    /**
     * 保存日志和销售简报关联信息
     *
     * @param logId 日志ID
     * @param type  1 代表需要销售简报 其余为不需要
     */
    private void saveLogRecord(Long logId, Integer getGetBulletin, Integer type) {
        //未开启直接跳过
        if (!Objects.equals(1, getGetBulletin)) {
            //无需关联销售简报
            return;
        }

        Date startTime, endTime;
        Date now = new Date();
        switch (type) {
            case 2:
                startTime = DateUtil.beginOfWeek(now);
                endTime = DateUtil.endOfWeek(now);
                break;
            case 3:
                startTime = DateUtil.beginOfMonth(now);
                endTime = DateUtil.endOfMonth(now);
                break;
            default:
                startTime = DateUtil.beginOfDay(now);
                endTime = DateUtil.endOfDay(now);
                break;
        }
        UserInfo userInfo = UserUtil.getUser();
        JSONObject record = getBaseMapper().queryBulletinByLog(Collections.singletonList(userInfo.getUserId()), startTime, endTime);
        OaLogRecord logRecord = BeanUtil.toBean(record, OaLogRecord.class);
        logRecord.setLogId(logId);
        logRecord.setCreateTime(LocalDateTimeUtil.now());
        logRecordService.save(logRecord);
        List<OaLogBulletin> bulletinList = getBaseMapper().queryBulletinByLogInfo(Collections.singletonList(userInfo.getUserId()), startTime, endTime);
        bulletinList.forEach(bulletin -> {
            bulletin.setLogId(logId);
            bulletin.setCreateTime(LocalDateTimeUtil.now());
        });
        logBulletinService.saveBatch(bulletinList);

    }


    /**
     * 获取规则的一些统计数据
     *
     * @param detail 模板配置详情
     * @return
     */
    private JSONObject getCycleTime(OaLogTemplateConfigVO detail) {
        OaLogRule rule = detail.getLogRule();
        Integer type = rule.getType();
        List<Long> userIdList = new ArrayList<>();
        // 适用范围代表范围是全部员工
        if (CollUtil.isEmpty(detail.getDeptIds()) && CollUtil.isEmpty(detail.getUserIds())) {
            userIdList.addAll(adminService.queryUserList(2).getData());
        }
        // 配置的适用范围 部门
        if (CollUtil.isNotEmpty(detail.getDeptIds())) {
            Result<List<Long>> result = adminService.queryUserByDeptIds(detail.getDeptIds());
            userIdList.addAll(result.getData());
        }
        // 配置的适用范围 员工
        if (CollUtil.isNotEmpty(detail.getUserIds())) {
            userIdList.addAll(detail.getUserIds());
        }

        userIdList = CollUtil.distinct(userIdList);
        if (!UserUtil.isAdmin()) {
            List<Long> data = adminService.queryChildUserId(UserUtil.getUserId()).getData();
            data.add(UserUtil.getUserId());
            userIdList.retainAll(data);
        }
        Integer totalNum = userIdList.size();
        String start = "";
        String end = "";
        // 日报
        if (type.equals(1)) {
            Integer dayOfWeek = DateUtil.dayOfWeek(new Date());
            //dayOfWeek 是 1 周日 2-7 周一到周六 数据库是 1-6 周一到周六 7 周日 所以要转换下
            dayOfWeek = dayOfWeek.equals(0) ? 7 : dayOfWeek - 1;
            String[] effectiveDayArr = rule.getEffectiveDay().split(",");
            List<Integer> dayList = Arrays.stream(effectiveDayArr).map(Integer::parseInt).collect(Collectors.toList());
            if (!dayList.contains(dayOfWeek)) {
                return new JSONObject();
            }
            String nowDay = DateUtil.format(new Date(), "yyyy-MM-dd");
            start = nowDay + " " + rule.getStartTime();
            end = nowDay + " " + rule.getEndTime();
        }
        // 周报
        else if (type.equals(2)) {
            Date beginDay = DateUtil.beginOfWeek(new Date());
            DateTime startDate = DateUtil.beginOfDay(DateUtil.offsetDay(beginDay, rule.getStartDay() - 1));
            start = DateUtil.format(startDate, "yyyy-MM-dd") + " 00:00";
            DateTime endDate = DateUtil.endOfDay(DateUtil.offsetDay(beginDay, rule.getEndDay() - 1));
            end = DateUtil.format(endDate, "yyyy-MM-dd") + " 12:00";
        }
        // 月报
        else if (type.equals(3)) {
            Date beginDay = DateUtil.beginOfMonth(new Date());
            DateTime startDate = DateUtil.beginOfDay(DateUtil.offsetDay(beginDay, rule.getStartDay() - 1));
            start = DateUtil.format(startDate, "yyyy-MM-dd") + " 00:00";
            int day = DateUtil.dayOfMonth(DateUtil.endOfMonth(new Date()));
            DateTime endDate = DateUtil.endOfDay(DateUtil.offsetDay(beginDay, day > rule.getEndDay() ? rule.getEndDay() - 1 : day));
            end = DateUtil.format(endDate, "yyyy-MM-dd") + " 12:00";
        }

        return new JSONObject()
                .fluentPut("start", start)
                .fluentPut("end", end)
                .fluentPut("userIds", userIdList)
                .fluentPut("totalNum", totalNum)
                .fluentPut("type", detail.getId());
    }

    private void queryLogDetail(JSONObject object, Long userId, Map<Long, CrmRelationDTO> relationDTOMap) {
        List<FileEntity> fileEntities = new ArrayList<>();
        String batchId = "batchId";
        if (StrUtil.isNotEmpty(object.getString(batchId))) {
            fileEntities.addAll(adminFileService.queryFileList(object.getString("batchId")).getData());
        }
        Map<String, List<FileEntity>> collect = fileEntities.stream().collect(Collectors.groupingBy(FileEntity::getFileType));
        if (collect.isEmpty()) {
            object.put("img", new ArrayList<>());
            object.put("file", new ArrayList<>());
        } else {
            object.putAll(collect);
            String img = "img";
            String file = "file";
            if (collect.get(img) == null) {
                object.put("img", new ArrayList<>());
            }
            if (collect.get(file) == null) {
                object.put("file", new ArrayList<>());
            }
        }

        Long logId = object.getLong("logId");
        object.put("favourUser", oaLogUserFavourService.queryFavourLogUserList(logId));
        object.put("isFavour", oaLogUserFavourService.queryUserWhetherFavourLog(logId));

        List<String> sendUserIds = StrUtil.splitTrim(object.getString("sendUserIds"), Const.SEPARATOR);
        if (!sendUserIds.isEmpty()) {
            object.put("sendUserList", UserCacheUtil.getSimpleUsers(sendUserIds.stream().map(Long::valueOf).collect(Collectors.toList())));
        } else {
            object.put("sendUserList", new ArrayList<>());
        }
        List<String> sendDeptIds = StrUtil.splitTrim(object.getString("sendDeptIds"), Const.SEPARATOR);
        if (!sendDeptIds.isEmpty()) {
            object.put("sendDeptList", UserCacheUtil.getDeptList(sendDeptIds));
        } else {
            object.put("sendDeptList", new ArrayList<>());
        }

        // 放入关系数据
        if (!CollectionUtil.isEmpty(relationDTOMap) && relationDTOMap.containsKey(logId)) {
            object.putAll(BeanUtil.beanToMap(relationDTOMap.get(logId)));
        }
        // 放入创建人信息，能否编辑删除信息
        OaLogVO oaLogVO = BeanUtil.copyProperties(object, OaLogVO.class);
        this.handleLogCreateUserInfo(oaLogVO, UserCacheUtil.getSimpleUser(object.getLong("createUserId")), UserUtil.getUserId());
        JSONObject result = BeanUtil.copyProperties(oaLogVO, JSONObject.class);
        object.putAll(result);

        if (!Objects.equals(0, object.getInteger("getBulletin"))) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("customerCount", object.get("customerCount"));
            jsonObject.put("businessCount", object.get("businessCount"));
            jsonObject.put("contractCount", object.get("contractCount"));
            jsonObject.put("receivablesMoney", object.get("receivablesMoney"));
            jsonObject.put("recordCount", object.get("recordCount"));
            object.put("bulletin", jsonObject);
        }
    }

    @Override
    public JSONObject queryById(Long logId) {
        OaLog byId = getById(logId);
        if (byId == null) {
            throw new CrmException(OaCodeEnum.LOG_ALREADY_DELETE);
        }
        // 查询日志数据
        JSONObject jsonObject = getBaseMapper().queryById(logId);
        // 扩展字段值
        oaLogDataService.setData(jsonObject, logId);

        // 查询relationMap
        Map<Long, CrmRelationDTO> relationMap = this.getOaLogRelationMap(Collections.singletonList(logId));
        queryLogDetail(jsonObject, UserUtil.getUserId(), relationMap);
        return jsonObject;
    }

    @Override
    public List<Map<String, Object>> export(LogBO logBO) {
        JSONObject object = this.getLogListObject(logBO);
        // 查询导出数据
        List<JSONObject> recordList = getBaseMapper().queryExportList(object);
        if (CollUtil.isEmpty(recordList)) {
            throw new CrmException(OaCodeEnum.LOG_EMPTY_EXPORT_ERROR);
        }
        // 获取logIds
        List<Long> logIds = getLogIds(recordList);
        // 获取日志业务关系map
        Map<Long, CrmRelationDTO> oaLogRelationMap = getOaLogRelationMap(logIds);
        // 定义list
        List<Map<String, Object>> list = new ArrayList<>();
        recordList.forEach((record -> {
            String sendName = "";
            if (StrUtil.isNotEmpty(record.getString("sendUserName"))) {
                sendName = sendName + record.getString("sendUserName") + ",";
            }
            if (StrUtil.isNotEmpty(record.getString("sendDeptName"))) {
                sendName = sendName + record.getString("sendDeptName") + ",";
            }
            if (StrUtil.isNotEmpty(sendName)) {
                sendName = sendName.substring(0, sendName.length() - 1);
            }
            // 拼接评论回复内容
            List<JSONObject> commentList = getBaseMapper().queryCommentList(record.getLong("logId"));
            StringBuilder stringBuilder = new StringBuilder();
            commentList.forEach(comment -> {
                stringBuilder.append(comment.getString("createUserName")).append("：");
                if (!comment.getInteger("mainId").equals(0)) {
                    stringBuilder.append("@").append(comment.getString("replyName")).append(" ");
                }
                stringBuilder.append(comment.getString("content")).append("\n");
            });
            // 获取关系业务
            CrmRelationDTO logRelationDTO = oaLogRelationMap.get(record.getLong("logId"));
            // 扩展字段值
            oaLogDataService.setData(record, record.getLong("logId"));
            list.add(record.fluentPut("sendName", sendName).fluentPut("relateCrmWork", CrmRelationUtils.getRelateCrmWork(logRelationDTO)).fluentPut("comment", HtmlUtil.unescape(HtmlUtil.cleanHtmlTag(stringBuilder.toString().trim()))));
        }));
        return list;
    }


    /**
     * app某个查询数量功能，没有名称
     */
    @Override
    public OaBusinessNumVO queryOaBusinessNum() {
        Dict dict = Dict.create();
        dict.put("userId", UserUtil.getUserId());
        Date date = new Date();
        dict.put("startTime", DateUtil.offsetDay(date, -30));
        dict.put("stopTime", date);
        dict.put("beginTime", DateUtil.beginOfMonth(date));
        dict.put("endTime", DateUtil.endOfMonth(date));
        return getBaseMapper().queryOaBusinessNum(dict);
    }


    /**
     * 处理bo对象
     *
     * @param bo bo
     * @return void
     * @author jiao sir
     * @date 2021/8/3
     */
    private void handleLogBo(LogBO bo) {
        Long userId = UserUtil.getUserId();
        String type = bo.getType();
        // 日期类型
        boolean is30 = "recent30".equals(type);
        boolean is60 = "recent60".equals(type);
        // 类型 0全部 1我发出的 2我收到的
        Integer by = bo.getBy() != null ? bo.getBy() : 0;
        bo.setBy(by);
        // 设置判断天数
        if (is30) {
            bo.setRecentDays(30);
        } else if (is60) {
            bo.setRecentDays(60);
        } else {
            bo.setRecentDays(null);
        }
        boolean isAdmin = UserUtil.isAdmin();

        if ((!by.equals(1) && StrUtil.isNotEmpty(bo.getCreateUserId())) || ObjectUtil.isNotEmpty(bo.getDeptIds())) {
            bo.setIsSearch(true);
        }

        List<Long> searchUserIds = new ArrayList<>();
        Set<Long> userIds = new HashSet<>();
        if (by.equals(TWO) || by.equals(0)) {
            List<Long> childUserIdList = new ArrayList<>();
            if (by.equals(0)) {
                childUserIdList = adminService.queryChildUserId(userId).getData();
            }
            // 获取入参的用户筛选ids
            List<Long> createUserIds = StrUtil.splitTrim(bo.getCreateUserId(), Const.SEPARATOR).stream().map(Long::valueOf).collect(Collectors.toList());
            bo.setIsAdmin(isAdmin);

            searchUserIds.addAll(createUserIds);
            // 获取入参的创建用户列表
            if (createUserIds.isEmpty() && bo.getDeptIds().isEmpty()) {
                bo.setNoCreateUserId(true);
                if (!isAdmin) {
                    userIds.addAll(childUserIdList);
                }
            } else {
                bo.setNoCreateUserId(false);
                if (!isAdmin) {
                    createUserIds.retainAll(childUserIdList);
                }
                userIds.addAll(createUserIds);
            }
            if (CollUtil.isNotEmpty(bo.getDeptIds())) {
                List<Long> data = adminService.queryUserByDeptIds(bo.getDeptIds()).getData();
                searchUserIds.addAll(data);
                if (!isAdmin) {
                    data.retainAll(childUserIdList);
                }
                // 添加部门用户列表
                userIds.addAll(data);
            }
        }

        bo.setUserIds(userIds);
        bo.setSearchUserIds(searchUserIds);
        // 设置接受人id
        bo.setSendUserId(userId);
        bo.setSendDeptId(UserUtil.getUser().getDeptId());
        bo.setCreateUserId(userId + "");

        if (!is30 && !is60 && bo.getType() != null) {
            BiParams biParams = new BiParams();
            biParams.setType(bo.getType());
            BiTimeUtil.BiTimeEntity recordInfo = BiTimeUtil.analyzeTime(biParams);
            bo.setSqlDateFormat(recordInfo.getSqlDateFormat());
            bo.setBeginTime(recordInfo.getBeginTime());
            bo.setFinalTime(recordInfo.getFinalTime());
            // 其他情况 是否有时间判断
        } else if (bo.getStartTime() != null) {
            int beginTime = Integer.parseInt(LocalDateTimeUtil.format(bo.getStartTime(), "yyyyMMdd"));
            int finalTime = Integer.parseInt(LocalDateTimeUtil.format(bo.getEndTime() != null ? bo.getEndTime() : LocalDate.now(), "yyyyMMdd"));
            bo.setSqlDateFormat("%Y%m%d");
            bo.setBeginTime(beginTime);
            bo.setFinalTime(finalTime);
        }
    }


    /**
     * 处理日志列表
     *
     * @param oaLogList 日志列表
     * @date 2021/7/31
     */
    private void handleLogList(List<OaLogVO> oaLogList) {
        if (!CollectionUtils.isEmpty(oaLogList)) {
            int listSize = oaLogList.size();
            Long userId = UserUtil.getUserId();
            // 获取日志ids
            List<Long> logIds = new ArrayList<>(listSize);
            // 获取批次ids
            List<String> batchIds = new ArrayList<>(listSize);
            // 定义创建用户列表
            Set<Long> createUserIds = new HashSet<>(listSize);
            // 首次处理
            oaLogList.forEach(oaLogVO -> {
                logIds.add(oaLogVO.getLogId());
                if (StrUtil.isNotEmpty(oaLogVO.getBatchId())) {
                    batchIds.add(oaLogVO.getBatchId());
                }
                createUserIds.add(oaLogVO.getCreateUserId());
            });
            // 查询创建人信息
            Map<Long, SimpleUser> createUserMap = UserCacheUtil.getSimpleUsers(createUserIds)
                    .stream()
                    .collect(Collectors.toMap(SimpleUser::getUserId, user -> user));
            // 查询recordMap
            Map<Long, OaLogRecord> recordMap = logRecordService
                    .lambdaQuery()
                    .select(OaLogRecord::getLogId, OaLogRecord::getCustomerNum, OaLogRecord::getBusinessNum, OaLogRecord::getContractNum, OaLogRecord::getReceivablesMoney, OaLogRecord::getActivityNum)
                    .in(OaLogRecord::getLogId, logIds)
                    .list().stream().collect(Collectors.toMap(OaLogRecord::getLogId, record -> record));
            // 查询relationMap
            Map<Long, CrmRelationDTO> relationMap = getOaLogRelationMap(logIds);
            // 查询batchMap
            Map<String, List<FileEntity>> batchFileMap = adminFileService
                    .queryFileList(batchIds)
                    .getData().stream().collect(Collectors.groupingBy(FileEntity::getBatchId));
            // 定义batchListMap
            Map<String, Map<String, List<FileEntity>>> batchFileListMap = new HashMap<>(batchFileMap.size());
            // 处理
            batchFileMap.forEach((k, v) -> batchFileListMap.put(k, v.stream().collect(Collectors.groupingBy(FileEntity::getFileType))));
            // 查询点赞用户列表
            List<OaLogUserFavour> userFavourList = oaLogUserFavourService
                    .lambdaQuery()
                    .select(OaLogUserFavour::getUserId, OaLogUserFavour::getLogId)
                    .in(OaLogUserFavour::getLogId, logIds)
                    .list();
            // 定义点赞用户列表
            Map<Long, SimpleUser> simpleUserMap = UserCacheUtil
                    .getSimpleUsers(userFavourList.stream().map(OaLogUserFavour::getUserId).distinct().collect(Collectors.toList()))
                    .stream()
                    .collect(Collectors.toMap(SimpleUser::getUserId, user -> user));
            // 定义点赞用户map
            Map<Long, List<SimpleUser>> favourUserListMap = new HashMap<>(logIds.size());
            // 遍历
            userFavourList.forEach(favourUser -> {
                SimpleUser simpleUser = simpleUserMap.get(favourUser.getUserId());
                List<SimpleUser> simpleUsers = favourUserListMap.computeIfAbsent(favourUser.getLogId(), k -> new ArrayList<>());
                simpleUsers.add(simpleUser);
            });
            // 查询评论数量
            Map<Long, Map<String, Object>> logCommentNum = getBaseMapper().queryLogCommentNum(logIds);
            //处理自定义字段信息
            List<Long> longs = oaLogList.stream().map(OaLogVO::getCategoryId).collect(Collectors.toList());
            Map<Long, List<OaLogTemplateFieldVO>> configMap = oaLogTemplateFieldService.queryConfigMap(longs);
            //处理扩展字段信息
            Map<Long, JSONObject> logDataMap = oaLogDataService.queryBatchData(logIds);
            // 处理数据
            oaLogList.forEach(oaLogVO -> {
                Long logId = oaLogVO.getLogId();
                // 处理附件
                oaLogVO.setImg(batchFileListMap
                        .getOrDefault(oaLogVO.getBatchId(), Collections.emptyMap())
                        .getOrDefault("img", Collections.emptyList()));
                oaLogVO.setFile(batchFileListMap
                        .getOrDefault(oaLogVO.getBatchId(), Collections.emptyMap())
                        .getOrDefault("file", Collections.emptyList()));
                // 处理点赞用户
                List<SimpleUser> favourUserList = favourUserListMap.getOrDefault(logId, Collections.emptyList());
                oaLogVO.setFavourUser(favourUserList);
                // 判断当前用户是否点赞
                oaLogVO.setIsFavour(favourUserList.stream().anyMatch(user -> user.getUserId().equals(userId)));
                // 处理发送用户id
                List<String> sendUserIds = StrUtil.splitTrim(oaLogVO.getSendUserIds(), Const.SEPARATOR);
                if (!sendUserIds.isEmpty()) {
                    oaLogVO.setSendUserList(UserCacheUtil.getSimpleUsers(sendUserIds.stream().map(Long::valueOf).collect(Collectors.toList())));
                }
                // 处理发送部门id
                List<String> sendDeptIds = StrUtil.splitTrim(oaLogVO.getSendDeptIds(), Const.SEPARATOR);
                if (!sendDeptIds.isEmpty()) {
                    oaLogVO.setSendDeptList(UserCacheUtil.getDeptList(sendDeptIds));
                }
                // 处理日志关系
                CrmRelationDTO crmRelationDTO = relationMap.get(logId);
                if (crmRelationDTO != null) {
                    oaLogVO.setCustomerList(crmRelationDTO.getCustomerList());
                    oaLogVO.setBusinessList(crmRelationDTO.getBusinessList());
                    oaLogVO.setContractList(crmRelationDTO.getContractList());
                    oaLogVO.setContactsList(crmRelationDTO.getContactsList());
                }
                // TODO 是否可编辑可删除
                // 处理创建人信息
                handleLogCreateUserInfo(oaLogVO, createUserMap.get(oaLogVO.getCreateUserId()), userId);
                // 处理记录信息
                handleLogRecord(oaLogVO, recordMap.get(logId));
                // 处理评论数量
                oaLogVO.setReplyNum(logCommentNum.containsKey(logId) ? logCommentNum.get(logId).get("num") : 0);
                List<OaLogTemplateFieldVO> templateFieldVOS = new ArrayList<>();
                List<OaLogTemplateFieldVO> oaLogTemplateFieldVOList = configMap.get(oaLogVO.getCategoryId());
                for (OaLogTemplateFieldVO field : oaLogTemplateFieldVOList) {
                    OaLogTemplateFieldVO fieldVO = BeanUtil.copyProperties(field, OaLogTemplateFieldVO.class);
                    Object value = null;
                    switch (fieldVO.getFieldName()) {
                        case "content": {
                            value = oaLogVO.getContent();
                            break;
                        }
                        case "tomorrow": {
                            value = oaLogVO.getTomorrow();
                            break;
                        }
                        case "question": {
                            value = oaLogVO.getQuestion();
                            break;
                        }
                        default: {
                            JSONObject jsonObject = logDataMap.get(logId);
                            if (jsonObject != null) {
                                value = jsonObject.get(StrUtil.toCamelCase(fieldVO.getFieldName()));
                            }
                        }
                    }
                    if (ObjectUtil.isEmpty(value)) {
                        fieldVO.setValue(null);
                    } else {
                        Object dataValue = FieldUtil.format2Object(value, fieldVO.getType());
                        fieldVO.setValue(dataValue);
                    }
                    templateFieldVOS.add(fieldVO);
                }
                oaLogVO.setFieldList(templateFieldVOS);
            });
        }
    }

    @Override
    public List<OaLogTemplateFieldVO> information(Long id) {
        OaLog one = this.lambdaQuery().select(OaLog::getCategoryId).eq(OaLog::getLogId, id).one();
        return oaLogTemplateFieldService.information(id, one.getCategoryId());
    }

    @Override
    public void exportLog(OaLogExportBO logBO, HttpServletResponse response) {
        // 导出的数据
        List<Map<String, Object>> list = this.export(logBO);
        List<Long> fieldIds = logBO.getFieldIds();
        if (ObjectUtil.isNotNull(fieldIds)) {
            Long categoryId = logBO.getCategoryId();
            if (ObjectUtil.isNotNull(categoryId)) {
                List<OaLogTemplateFieldVO> allFields = oaLogTemplateFieldService.queryExportFields(categoryId);
                // 表格的标题list
                List<ExcelParseUtil.ExcelDataEntity> titleList = allFields.stream()
                        .filter(f -> fieldIds.contains(f.getFieldId()))
                        .map(m -> BeanUtil.copyProperties(m, ExcelParseUtil.ExcelDataEntity.class))
                        .collect(Collectors.toList());
                ExcelParseUtil.exportExcel(list, new ExcelParseUtil.ExcelParseService() {
                    @Override
                    public ExcelParseUtil.DataFunc getFunc() {
                        return (record, headMap) -> {
                            for (String fieldName : headMap.keySet()) {
                                record.put(fieldName, ActionRecordUtil.parseExportValue(record.get(fieldName), headMap.get(fieldName), false));
                            }
                        };
                    }

                    @Override
                    public String getExcelName() {
                        return "日志";
                    }

                    @Override
                    public boolean isXlsx() {
                        return true;
                    }
                }, titleList, response, logBO.getIsXls());
            }
        }
    }

    @Override
    public void updateLogRelId(Integer type, Long oldId, Long newId) {
        boolean exists = logRelationService.lambdaQuery().eq(OaLogRelation::getRelationId, oldId).eq(OaLogRelation::getType, type).exists();
        if (exists) {
            logRelationService.lambdaUpdate().set(OaLogRelation::getRelationId, newId).eq(OaLogRelation::getRelationId, oldId).eq(OaLogRelation::getType, type).update();
        }
    }


    /**
     * 处理日志VO对象的创建信息
     *
     * @param oaLogVO          日志对象
     * @param createSimpleUser 创建用户
     * @param userId           当前用户id
     * @return void
     * @author jiao sir
     * @date 2021/7/31
     */
    private void handleLogCreateUserInfo(OaLogVO oaLogVO, SimpleUser createSimpleUser, Long userId) {
        // 处理创建人信息
        Long createUserId = oaLogVO.getCreateUserId();
        oaLogVO.setUserImg(createSimpleUser.getImg());
        oaLogVO.setDeptId(createSimpleUser.getDeptId());
        oaLogVO.setRealname(createSimpleUser.getRealname());
        oaLogVO.setCreateUser(createSimpleUser);
        // TODO 日志创建者self需要根据模板规则限制；上级只能在72小时内删除
        // 是否是自己 1是0否
        int isEdit = userId.equals(createUserId) ? 1 : 0;
        int isDel = 0;
        // self
        if (ObjectUtil.equal(1, isEdit)) {
            // 模板配置 不可以编辑
            if (ObjectUtil.equal(oaLogVO.getModifyFlag(), 1)) {
                isEdit = 0;
            }
            // 模板配置 0不允许员工删除提交的日志
            if (ObjectUtil.equal(oaLogVO.getDeleteFlag(), 0)) {
                isDel = 0;
            }
            // 1仅允许删除24小时内提交的日志
            else if (ObjectUtil.equal(oaLogVO.getDeleteFlag(), 1)) {
                LocalDateTime now = LocalDateTime.now();
                LocalDateTime createTime = oaLogVO.getCreateTime();
                long millis = Duration.between(createTime.plusHours(24L), now).toMillis();
                isDel = millis >= 0 ? 0 : 1;
            }
            // 2允许员工删除提交的日志
            else {
                isDel = 1;
            }
        }
        // not self
        else {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime createTime = oaLogVO.getCreateTime();
            long millis = Duration.between(createTime.plusHours(24L * 3), now).toMillis();
            if (millis < 0) {
                // 找当前登录用户的下级list，是否包含日志创建者
                List<Long> list = UserCacheUtil.queryChildUserId(userId);
                if (CollUtil.isNotEmpty(list)) {
                    if (list.contains(createUserId)) {
                        isDel = 1;
                    }
                }
            }
        }
        // 设置编辑信息
        oaLogVO.setPermission(new JSONObject().fluentPut("isUpdate", isEdit).fluentPut("isDelete", isDel));
    }

    private List<Long> getLogIds(List<JSONObject> pageList) {
        // 获取logIds
        return pageList.stream().map(r -> r.getLong("logId")).collect(Collectors.toList());
    }

    /**
     * 处理日志关联
     *
     * @param logId          日志id
     * @param type           类型
     * @param relationIds    关系ids
     * @param oaLogRelations 关系列表
     * @author jiao sir
     * @date 2021/11/19
     */
    private void handleOaLogRelation(Long logId, int type, String relationIds, List<OaLogRelation> oaLogRelations, List<Long> longs) {
        SeparatorUtil.toLongSet(relationIds)
                .forEach(id -> {
                    OaLogRelation build = OaLogRelation
                            .builder()
                            .logId(logId)
                            .relationId(id)
                            .type(type)
                            .build();
                    oaLogRelations.add(build);
                    longs.add(id);
                });
    }

    /**
     * 处理日志记录信息
     *
     * @param oaLogVO     日志对象
     * @param oaLogRecord 记录信息
     * @return void
     * @author jiao sir
     * @date 2021/7/31
     */
    private void handleLogRecord(OaLogVO oaLogVO, OaLogRecord oaLogRecord) {
        if (oaLogRecord != null) {
            oaLogVO.setCustomerCount(oaLogRecord.getCustomerNum());
            oaLogVO.setBusinessCount(oaLogRecord.getBusinessNum());
            oaLogVO.setContractCount(oaLogRecord.getContractNum());
            oaLogVO.setReceivablesMoney(oaLogRecord.getReceivablesMoney());
            oaLogVO.setRecordCount(oaLogRecord.getActivityNum());
            oaLogVO.setGetBulletin(1);
            oaLogVO.setBulletin(new OaLogVO.OaLogRecordBulletin(oaLogRecord.getContractNum(),
                    oaLogRecord.getReceivablesMoney(),
                    oaLogRecord.getActivityNum(),
                    oaLogRecord.getBusinessNum(),
                    oaLogRecord.getCustomerNum()));
        } else {
            oaLogVO.setGetBulletin(0);
        }
    }


    /**
     * 获取日志关系map
     *
     * @param logIds 日志ids
     * @return java.util.Map<java.lang.Integer, com.kakarote.oa.entity.DTO.OaLogRelationDTO>
     * @author jiao sir
     * @date 2021/8/4
     */
    private Map<Long, CrmRelationDTO> getOaLogRelationMap(List<Long> logIds) {
        // 查询日志关系
        List<OaLogRelation> oaLogRelations = logRelationService
                .lambdaQuery()
                .select(OaLogRelation::getRelationId, OaLogRelation::getType, OaLogRelation::getLogId)
                .in(OaLogRelation::getLogId, logIds)
                .list();
        // 获取日志关系map
        Map<Integer, Map<Long, Set<Long>>> logRelationMap = oaLogRelations
                .stream()
                .collect(Collectors.groupingBy(OaLogRelation::getType,
                        Collectors.groupingBy(OaLogRelation::getLogId, Collectors.mapping(OaLogRelation::getRelationId, Collectors.toSet()))));
        Set<Long> ids = oaLogRelations
                .stream()
                .map(OaLogRelation::getLogId)
                .collect(Collectors.toSet());
        return CrmRelationUtils.getCrmRelationMap(logRelationMap, ids);
    }

}
